﻿#pragma once

#include "../Controller.h"

#include <boost/signal.hpp>

#include "../TurnController.h"
#include "../../domain/configuration/GameEndReasons.h"
#include "../../views/abstract/IGameplayView.h"
#include "../../utils/gui/Form.h"

namespace Controllers {
	class GameplayController: public Controller
	{
	protected:
		boost::signal<void ()> gameStartEvent; /**< Zdarzenie rozpoczecia gry */
		boost::signal<void ()> playersSetEvent; /**< Zdarzenie ustawienia kolejki graczy */
		boost::signal<void ()> cardsDealEvent; /**< Zdarzenie rozdania kart */

		Views::IGameplayView* view;
		Utils::GUI::Form* form;

		TurnController* turn_controller;

		Players::PlayersQueue players; /**< Kolejka graczy */
		Players::Player* starting_player; /**< Gracz rozpoczynający rozgrywkę */
		Players::Player* current_player; /**<  Gracz aktualnie wykonujący ruch */
		Cards::CardSet searched_cards; /**<  Poszukiwane przez graczy karty */
		Cards::CardsCollection cards; /**<  Wszystkie karty w grze */
		Players::Player* winner; /**< Zwycięzca rozgrywki, lub NULL, jeśli rozgrywka nie jest jeszcze rozstrzygnięta */

	public:
		/**
		* Zdarzenie wygrania gry.
		* @param player Gracz, który wygrał grę
		* @param searched_cards Poszukiwane karty
		* @param reason Przyczyna zakończenia gry
		*/
		boost::signal<void (Players::Player*, Cards::CardSet, Domain::Configuration::GAME_END_REASON)> gameWonEvent;
		/**
		* Zdarzenie przegrania gry. Klasa podrzędna moze je wywołać, gdy chce zakomunikować użytkownikowi programu o jego porażce
		* @see gameWonEvent
		*/
		boost::signal<void (Players::Player*, Cards::CardSet, Domain::Configuration::GAME_END_REASON)> gameLostEvent;

		/** Konstruktor kontrolera gry. Ustawia dostępne karty w grze korzystając z danych konfiguracyjnych */
		GameplayController(Utils::GUI::Form*);
		virtual ~GameplayController();

		virtual void startGame(); /**< Rozpoczyna rozgrywkę, pyta o wybór graczy */
		/**
		* Kończy grę z podanej przyczyny
		* @param reason Przyczyna końca gry
		*/
		virtual void endGame(Domain::Configuration::GAME_END_REASON);

		virtual bool isGameEnded(); /**< Sprawdza, czy gra jest zakończona */
	protected:
		virtual void startRound(); /**< Rozpoczyna rundę gry */
		virtual void endRound(); /**< Kończy rundę gry */
		virtual void startTurn(); /**< Rozpoczyna turę dla pierwszego gracza z kolejki players */
		virtual void endTurn(); /**< Kończy turę i przesuwa kolejkę graczy, lub gdy nie ma wiecej aktywnych graczy, kończy grę */

		/**
		* Tworzy gracza i dodaje go do kolejki
		* @param card Karta, która zostanie przypisana graczowi
		* @param type Rodzaj gracza (np. czy klient łączący z serwerem)
		*/
		virtual Players::Player* createPlayer(Cards::PlayerCard*, Players::PLAYER_TYPE);
		/**
		* Tworzy kontroler tury, w zależności od typu kolejnego gracza.
		* Klasy podrzędne mają decydować, z jakimi parametrami wywoływać Controllers::TurnController.
		*/
		virtual TurnController* createTurnController() = 0;
		virtual void dealCards() = 0; /**< Klasy dziedziczące powinny nadpisać tę funkcje odpowiednią rozdającą graczom karty */
		virtual void excludePlayer(); /**< Wyklucza gracza (ustanawia go nieaktywnym) */
		/**
		* Sprawdza, z czy zostało więcej niż jeden gracz
		* @return Fałsz, jeśli jest tylko jeden aktywny gracz, lub nie ma ich wcale
		*/
		virtual bool hasMoreThanOneActivePlayer();
		/**
		* Przeszukuje kolejkę graczy w poszukiwaniu aktywnego gracza
		* @return Zwraca pierwszego aktywnego gracza w kolejce
		*/
		virtual Players::Player* findActivePlayer();
		virtual void nextPlayer(); /**< Przesuwa graczy w kolejce */
		virtual void pickPlayers(); /**< Wywołuje z widoku gry wybór graczy */
		virtual void setEvents(); /**< Ustawia wydarzenia sterujące wewnętrznym przebiegiem rozgrywki w kontrolerze */
		virtual void setLogger(); /**< Ustawia loggera */

		/**
		* Funkcja wywoływana po wyborze graczy w widoku
		* @param players_queue Kolejka par zawierających kartę gracza i jego typ
		*/
		virtual void onPlayersPicked(std::queue<std::pair<Cards::PlayerCard*, Players::PLAYER_TYPE>>);
		virtual void onPlayerWinDialogClose(); /**< Funkcja wywoływana po zamknięciu okna z informacją o wygranej gracza */
		virtual void onPlayerLoseDialogClose(); /**< Funkcja wywoływana po zamknięciu okna z informacją o porzegranej gracza */
		virtual void onGameWin(); /**<  Funkcja wywoływana po ustaleniu zwycięzcy gry */
	};
}

